import json
import logging
from http.client import responses

from click import prompt
from langchain.chains.question_answering.map_reduce_prompt import messages
from langchain.chains.summarize.refine_prompts import prompt_template
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, HumanMessagePromptTemplate

from exception.custom_exception import CustomErrorThrowException
from tools.demo_tool import get_tool_statements, weather_search, get_schema_statements, database_tool

chat_history = [

]

function_name = {
    "weather_search":weather_search,
    "get_schema_statements":get_schema_statements,
    "database_tool":database_tool
}


async def call_tool_by_name(tool_name: str, tool_input: dict):
    func = function_name.get(tool_name)
    return await func(**tool_input)


async def agent_chat(api_key: str, user_input: str):
    model = init_chat_model(model="deepseek-v3",
                            model_provider="openai",
                            api_key=api_key,
                            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
                            temperature=0.5
                            )

    prompt_text = """
    
    C - 上下文（Context）
    你是一个具有推理和问题分解能力的大语言模型。你可以在接收到一个问题后，先进行思考，然后根据问题的需要决定是否要调用某个工具。
    你不会直接调用工具，而是给出要调用的工具名称及其参数，由系统/用户帮你执行。执行结果将由外部系统再提供给你，供你继续推理下一步。
    
    🎯 O - 目标（Objective）
    你的目标是通过逐步推理和工具辅助，最终回答用户的问题。你需要：
    明确每一步的思考（thought）
    如果需要工具：提供工具名称（tool）和参数（input）
    如果不需要工具：说明你可以直接得出结论
    等待工具执行结果后，继续推理，直到给出最终结果（final_answer）
    
    ✍️ S - 风格（Style）
    使用结构化 JSON 表达每一步，格式包括：
    thought：你当前的思考
    action：若需要工具调用，包含 tool 和 input 字段；若无需工具，为 null
    不包含 observation（因为你还没拿到）
    
    🎙 T - 语气（Tone）
    语气理性、清晰、有条理，如助手或分析员，适合执行任务型对话。
    
    👥 A - 受众（Audience）
    直接读者：大语言模型，用于分步骤回答复杂问题
    中间执行者：系统或人类操作员，负责执行 action 并把结果返回给模型
    
    📦 R - 响应格式（Response Format）
    {{
      "question": "string，用户提出的问题",
      "step": {{
        "thought": "string，这一步你是如何思考的",
        "action": {{
          "tool": "string，需要调用的工具名称",
          "input": {{
            "key1": "value1"
          }}
        }}
      }}
    }}
    如果不需要工具调用，格式如下：其中结论是你当前的思考结果
    {{
      "question": "string，用户提出的问题",
      "step": {{
        "thought": "结论",
        "action": null
      }}
    }}
    
    注意：
    1.输出的 JSON 必须严格遵循上述格式，确保每个字段都存在且类型正确。不要带有markdown格式包含JSON数据或其他非 JSON 内容。
    2.特别是```json 数据 ``` 绝对不能出现用于包裹 JSON 数据的标记。
    3.一定不要markdown的格式输出。
    你能够调用的工具信息如下:
    {tool_name}
    
    """

    questions = f"我的问题是{user_input}"

    for i in range(10):
        prompt_template = ChatPromptTemplate.from_messages(
            [
                ("system",prompt_text),
                MessagesPlaceholder("chat_history"),
                ("human","{questions}")
            ]
        )

        messages = prompt_template.invoke({
            "questions": user_input,
            "chat_history": chat_history,
            "tool_name": await get_tool_statements()
        })

        chat_history.append(HumanMessage(content=questions))

        responses = model.invoke(input=messages)

        logging.info(f"本次的思考结果为{responses.content}")
        chat_history.append(AIMessage(content=responses.content))
        current_result = json.loads(responses.content)

        current_step = current_result.get("step",None)
        if current_step is None:
            logging.error("当前步骤没有返回结果，直接返回")
            raise CustomErrorThrowException(404,"当前步骤没有返回结果，直接返回")

        current_action = current_step.get("action",None)
        if current_action is None:
            result = current_step.get("thought","")
            logging.info("当前步骤没有返回action，模型认为可以直接结束并返回结果\n{result}")
            return result

        current_tool_name = current_action.get("tool",None)
        if current_tool_name is None:
            logging.error("当前思考需要使用工具，但工具名异常")
            raise CustomErrorThrowException(405,"当前思考需要使用工具，但工具名异常")


        current_tool_input = current_action.get("input",None)
        if current_tool_input is None:
            logging.error("当前思考需要使用工具，但工具参数异常")
            raise CustomErrorThrowException(406,"当前思考需要使用工具，但工具参数异常")

        logging.info(f"进入到实用工具环节，调用工具为{current_tool_name}，调用工具参数为{current_tool_input}")

        #开始调用工具
        tool_result = await call_tool_by_name(current_tool_name,current_tool_input)

        logging.info(f"本轮思考结果为：{tool_result}")

        questions = f"这是上一步利用工具思考获得的结果{tool_result},下一步继续思考我的问题{user_input}"
    return None